import java.util.ArrayList;

import static java.lang.System.out;

public final class QIterABMiniMaxDrawFix extends IterDeepDrawFix {

    int deepest = 0;

    public QIterABMiniMaxDrawFix(boolean isBlack, Eval evaluator, int maxDepth) {
        super(isBlack, evaluator, maxDepth);
    }


    @Override
    public Board findMove(Board b, ArrayList<Board> moves, int depth) {
        // IMPORTANT! If the player using findMove is White, then
        // the search method will be called with BLACK to move and
        // vice versa, i.e. THE RETURN VALUE FROM THE SEARCH-CALL WILL
        // REFLECT THE OPPONENTS BEST POSSIBLE SCORE

        int alpha = MIN;
        int beta = MAX;

        // If no moves found, return null as error flag
        if( moves.isEmpty() ) {
            return null;
        }

        // If only one possible move found - just return that.
        if( moves.size() == 1 ) {
            depthCount[0]++;
            return moves.get(0);
        }

	Board bestMove = moves.get(0);
	int nodeCount = 0;
    deepest = 0;
        while (  (nodeCount < moves.size())  &&  (alpha < beta)  ) {
            Board move = moves.get(nodeCount);
            int value = search(move, 0, depth, alpha, beta);
            if (isBlack) {
                if (value < beta) {
                    beta = value;
                    bestMove = move;
                }
            } else {
                if (value > alpha) {
                    alpha = value;
                    bestMove = move;
                }
            }
            nodeCount++;
        }
        out.println("Deepest search depth: " + deepest);

        int bestValue;
        if(isBlack) {
            bestValue = beta;
        } else {
            bestValue = alpha;
        }
        if(printBestMoveValue) {
            out.println("The best move has value " + bestValue);
        }

        return bestMove;
    }


    //public int search(Board board, int depthLeft, int alpha, int beta) {
    public int search(Board board, int depth, int maxDepth, int alpha, int beta) {
        nbrNodesVisited++;

	int depthLeft = maxDepth - depth;

        //quiescence prep
	boolean canJump = true;
        ArrayList<Board> moves = new ArrayList<Board>();
	board.generateJumps(moves);
	if(moves.size() == 0) {
	    board.generateSteps(moves);
	    canJump = false;
	}

        nbrMovesCount[moves.size()]++;

        //if unable to move, this is a losing board for current player
        //punish for depth left (embarrassing to lose with much depth left)
        if(moves.isEmpty()) {
            depthCount[depth]++;
            if (board.blackToMove) {
                return BLACK_LOSS+depthLeft;
            } else {
                return WHITE_LOSS-depthLeft;
            }
        }

        for(int i = 0; i < drawBoardsSize; i++) {
            if (board.isSame(drawBoards[i])) {
                depthCount[depth]++;
                if (isBlack) {
                    return DRAW;
                } else {
                    return -DRAW;
                }
            }
        }

	if (depth >= maxDepth && !canJump) {
	    if(depth > deepest) {
            deepest = depth;
	    }
        depthCount[depth]++;
	    return evaluator.eval(board);
    }

        depth++;
	int nodeCount = 0;
        while (  (nodeCount < moves.size())  &&  (alpha < beta)  ) {
	    Board move = moves.get(nodeCount);
	    int value = search(move, depth, maxDepth, alpha, beta);
            if (board.blackToMove) {
                if (value < beta) {
                    beta = value;
                }   
            } else {
                if (value > alpha) {
                    alpha = value;
                }
            }
	    nodeCount++;
        }


        int bestValue;
        if (board.blackToMove) {
            bestValue = beta;
        } else {
            bestValue = alpha;
        }

        return bestValue;
    }
}
